# -*- coding: utf-8 -*-
"""
A股股票日线数据同步模块
从akshare或tushare获取股票日线交易数据，并同步到数据库
"""
import logging
import pandas as pd
import akshare as ak
import tushare as ts
from datetime import datetime, timedelta
from typing import List, Dict, Any, Optional
from database import DatabaseManager, StockDailyDAO
from config import DATABASE_CONFIG, SYNC_CONFIG, DATA_SOURCE_CONFIG
from trading_calendar import TradingCalendar
import concurrent.futures
import time
import random

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class StockDailySync:
    """A股股票日线数据同步器"""
    
    def __init__(self):
        self.db_manager = DatabaseManager(DATABASE_CONFIG)
        self.daily_dao = StockDailyDAO(self.db_manager)
        self.trading_calendar = TradingCalendar()
        self.batch_size = SYNC_CONFIG.get('batch_size', 1000)
        self.request_delay = SYNC_CONFIG.get('request_delay', 0.35)  # Tushare延迟0.35秒
        self.max_retries = 3  # 最大重试次数
        self.consecutive_errors = 0  # 连续错误计数
        
        # 数据源配置
        self.data_source = DATA_SOURCE_CONFIG.get('data_source', 'tushare')
        self.tushare_token = DATA_SOURCE_CONFIG.get('tushare_token', '')
        
        # 初始化 Tushare
        if self.data_source == 'tushare' and self.tushare_token:
            try:
                # 方式1：直接使用token初始化，不使用set_token（避免tk.csv权限问题）
                self.tushare_pro = ts.pro_api(self.tushare_token)
                logger.info("Tushare API 初始化成功")
            except Exception as e:
                logger.error(f"Tushare API 初始化失败: {e}")
                logger.warning("将回退到 akshare 数据源")
                self.data_source = 'akshare'
        elif self.data_source == 'tushare' and not self.tushare_token:
            logger.warning("未配置 Tushare token，将使用 akshare 数据源")
            self.data_source = 'akshare'
        
        logger.info(f"当前使用数据源: {self.data_source}")
        
        # 股票最新同步日期缓存
        self.stock_latest_dates = {}
        self.cache_loaded = False
    
    def get_random_delay(self) -> float:
        """获取随机延迟时间，避免固定模式被检测"""
        return random.uniform(self.request_delay_min, self.request_delay_max)
    
    def load_stock_latest_dates(self, stock_codes: List[str] = None) -> None:
        """加载所有股票的最新同步日期到内存缓存"""
        try:
            if not stock_codes:
                stock_codes = self.get_stock_codes()
            
            logger.info(f"正在加载 {len(stock_codes)} 只股票的最新同步日期...")
            
            # 批量查询所有股票的最新日期
            placeholders = ','.join(['%s'] * len(stock_codes))
            sql = f"""
            SELECT stock_code, MAX(trade_date) as latest_date 
            FROM new_stock_daily 
            WHERE stock_code IN ({placeholders})
            GROUP BY stock_code
            """
            
            results = self.db_manager.execute_query(sql, stock_codes)
            
            # 构建缓存字典
            self.stock_latest_dates = {}
            for row in results:
                stock_code = row['stock_code']
                latest_date = row['latest_date']
                if latest_date:
                    # 转换为字符串格式
                    self.stock_latest_dates[stock_code] = latest_date.strftime('%Y%m%d')
                else:
                    # 如果没有数据，设为None
                    self.stock_latest_dates[stock_code] = None
            
            # 对于没有数据的股票，也添加到缓存中
            for stock_code in stock_codes:
                if stock_code not in self.stock_latest_dates:
                    self.stock_latest_dates[stock_code] = None
            
            self.cache_loaded = True
            logger.info(f"成功加载 {len(self.stock_latest_dates)} 只股票的最新同步日期")
            
        except Exception as e:
            logger.error(f"加载股票最新同步日期失败: {e}")
            self.cache_loaded = False
            raise
    
    def update_stock_latest_date(self, stock_code: str, latest_date: str) -> None:
        """更新指定股票的最新同步日期缓存"""
        if self.cache_loaded:
            self.stock_latest_dates[stock_code] = latest_date
    
    def get_latest_trade_date_cached(self, stock_code: str) -> str:
        """从缓存中获取股票的最新交易日期"""
        if not self.cache_loaded:
            # 如果缓存未加载，回退到数据库查询
            return self.get_latest_trade_date(stock_code)
        
        return self.stock_latest_dates.get(stock_code)
    
    def is_weekend(self, date_str: str) -> bool:
        """判断是否为周末"""
        try:
            date_obj = datetime.strptime(date_str, '%Y%m%d')
            # 0=Monday, 6=Sunday
            return date_obj.weekday() >= 5  # 5=Saturday, 6=Sunday
        except:
            return False
    
    def get_last_trading_day(self, date_str: str = None) -> str:
        """获取最后一个交易日（排除周末和节假日）"""
        if not date_str:
            date_str = datetime.now().strftime('%Y-%m-%d')
        
        # 使用交易日历获取上一个交易日
        prev_trading_day = self.trading_calendar.get_previous_trading_day(date_str)
        if prev_trading_day:
            return prev_trading_day.replace('-', '')
        
        # 如果交易日历获取失败，使用简单的周末判断
        current_date = datetime.strptime(date_str, '%Y-%m-%d')
        while self.is_weekend(current_date.strftime('%Y%m%d')):
            current_date -= timedelta(days=1)
        
        return current_date.strftime('%Y%m%d')
    
    def get_sync_end_date(self) -> str:
        """获取同步结束日期
        如果当前时间未超过15点，则不同步当天的数据
        """
        current_time = datetime.now()
        if current_time.hour < 15:
            # 如果当前时间未超过15点，使用上一个交易日
            logger.info(f"当前时间 {current_time.strftime('%H:%M')} 未超过15点，不同步当天数据")
            return self.get_last_trading_day()
        else:
            # 如果当前时间已超过15点，可以同步当天数据
            logger.info(f"当前时间 {current_time.strftime('%H:%M')} 已超过15点，可以同步当天数据")
            # 检查今天是否为交易日
            today = datetime.now().strftime('%Y-%m-%d')
            if self.trading_calendar.is_trading_day(today):
                return datetime.now().strftime('%Y%m%d')
            else:
                return self.get_last_trading_day()
    
    def get_next_trading_day(self, date_str: str) -> str:
        """获取下一个交易日（排除周末和节假日）"""
        # 转换日期格式
        if len(date_str) == 8:  # YYYYMMDD格式
            date_str = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}"
        
        # 使用交易日历获取下一个交易日
        next_trading_day = self.trading_calendar.get_next_trading_day(date_str)
        if next_trading_day:
            return next_trading_day.replace('-', '')
        
        # 如果交易日历获取失败，使用简单的周末判断
        current_date = datetime.strptime(date_str, '%Y-%m-%d')
        next_date = current_date + timedelta(days=1)
        while self.is_weekend(next_date.strftime('%Y%m%d')):
            next_date += timedelta(days=1)
        
        return next_date.strftime('%Y%m%d')
    
    def calculate_sync_dates(self, stock_code: str, max_days: int = 365) -> Dict[str, Any]:
        """计算股票需要同步的日期范围"""
        result = {
            'stock_code': stock_code,
            'needs_sync': False,
            'start_date': None,
            'end_date': None,
            'sync_days': 0,
            'reason': ''
        }
        
        try:
            # 获取该股票的最新交易日期
            latest_date = self.get_latest_trade_date(stock_code)
            
            # 获取同步结束日期（考虑15点限制）
            last_trading_day = self.get_sync_end_date()
            
            if latest_date:
                # 从最新日期的下一个交易日开始同步
                start_date = self.get_next_trading_day(latest_date)
                
                # 如果最新日期已经是最后一个交易日或更新，跳过同步
                if start_date > last_trading_day:
                    result['reason'] = f"数据已是最新（最新日期: {latest_date}，最后交易日: {last_trading_day}）"
                    return result
                
                end_date = last_trading_day
            else:
                # 如果没有历史数据，从max_days天前的最后一个交易日开始同步
                start_date_obj = datetime.now() - timedelta(days=max_days)
                start_date = self.get_last_trading_day(start_date_obj.strftime('%Y%m%d'))
                end_date = last_trading_day
            
            # 如果开始日期大于结束日期，说明没有需要同步的数据
            if start_date > end_date:
                result['reason'] = f"没有需要同步的数据（开始日期: {start_date}，结束日期: {end_date}）"
                return result
            
            # 使用交易日历计算需要同步的交易日数量
            start_date_str = f"{start_date[:4]}-{start_date[4:6]}-{start_date[6:8]}"
            end_date_str = f"{end_date[:4]}-{end_date[4:6]}-{end_date[6:8]}"
            
            trading_days = self.trading_calendar.get_trading_days(start_date_str, end_date_str)
            sync_days = len(trading_days)
            
            result['needs_sync'] = True
            result['start_date'] = start_date
            result['end_date'] = end_date
            result['sync_days'] = sync_days
            result['reason'] = f"需要同步 {sync_days} 个交易日的数据（{start_date} - {end_date}）"
            
        except Exception as e:
            result['reason'] = f"计算同步日期失败: {e}"
            logger.error(f"计算股票 {stock_code} 同步日期失败: {e}")
        
        return result
    
    def get_stock_codes(self, status_filter: str = 'active') -> List[str]:
        """获取指定状态的股票代码"""
        try:
            if status_filter == 'active':
                sql = "SELECT stock_code FROM new_stock_info WHERE status = 'active' ORDER BY stock_code"
                results = self.db_manager.execute_query(sql)
                stock_codes = [row['stock_code'] for row in results]
                logger.info(f"获取到 {len(stock_codes)} 只活跃股票")
            elif status_filter == 'all':
                sql = "SELECT stock_code FROM new_stock_info ORDER BY stock_code"
                results = self.db_manager.execute_query(sql)
                stock_codes = [row['stock_code'] for row in results]
                logger.info(f"获取到 {len(stock_codes)} 只股票（包含退市）")
            else:
                sql = "SELECT stock_code FROM new_stock_info WHERE status = %s ORDER BY stock_code"
                results = self.db_manager.execute_query(sql, (status_filter,))
                stock_codes = [row['stock_code'] for row in results]
                logger.info(f"获取到 {len(stock_codes)} 只{status_filter}股票")
            return stock_codes
        except Exception as e:
            logger.error(f"获取股票代码失败: {e}")
            raise
    
    def get_stock_sync_status(self) -> Dict[str, Dict[str, Any]]:
        """获取所有股票的同步状态信息"""
        try:
            sql = """
            SELECT 
                stock_code,
                stock_name,
                status,
                updated_at
            FROM new_stock_info 
            ORDER BY stock_code
            """
            results = self.db_manager.execute_query(sql)
            
            stock_status = {}
            for row in results:
                stock_status[row['stock_code']] = {
                    'stock_name': row['stock_name'],
                    'status': row['status'],
                    'updated_at': row['updated_at']
                }
            
            logger.info(f"获取到 {len(stock_status)} 只股票的同步状态")
            return stock_status
        except Exception as e:
            logger.error(f"获取股票同步状态失败: {e}")
            raise
    
    def get_latest_trade_date(self, stock_code: str) -> str:
        """获取指定股票的最新交易日期"""
        try:
            sql = "SELECT MAX(trade_date) as latest_date FROM new_stock_daily WHERE stock_code = %s"
            result = self.db_manager.execute_query(sql, (stock_code,))
            if result and result[0]['latest_date']:
                return result[0]['latest_date'].strftime('%Y%m%d')
            return None
        except Exception as e:
            logger.error(f"获取股票 {stock_code} 最新日期失败: {e}")
            return None
    
    def get_missing_trading_days(self, stock_code: str) -> List[str]:
        """获取指定股票缺失的交易日列表（使用缓存优化）"""
        try:
            # 从缓存获取股票的最新交易日期
            latest_date = self.get_latest_trade_date_cached(stock_code)
            
            if not latest_date:
                # 如果没有历史数据，从一年前开始
                start_date = (datetime.now() - timedelta(days=365)).strftime('%Y-%m-%d')
            else:
                # 从最新日期的下一天开始
                latest_dt = datetime.strptime(latest_date, '%Y%m%d')
                next_day = latest_dt + timedelta(days=1)
                start_date = next_day.strftime('%Y-%m-%d')
            
            # 获取同步结束日期（考虑15点限制）
            sync_end_date = self.get_sync_end_date()
            end_date = f"{sync_end_date[:4]}-{sync_end_date[4:6]}-{sync_end_date[6:8]}"
            
            # 获取交易日列表
            trading_days = self.trading_calendar.get_trading_days(start_date, end_date)
            
            # 如果交易日历获取失败，返回空列表
            if not trading_days:
                return []
            
            # 如果缓存已加载，直接使用缓存判断
            if self.cache_loaded:
                # 从缓存中获取最新日期，计算需要同步的日期范围
                if latest_date:
                    latest_dt = datetime.strptime(latest_date, '%Y%m%d')
                    # 过滤掉已同步的日期
                    missing_days = [day for day in trading_days 
                                  if datetime.strptime(day, '%Y-%m-%d') > latest_dt]
                else:
                    # 如果没有历史数据，所有交易日都需要同步
                    missing_days = trading_days
                
                return missing_days
            
            # 如果缓存未加载，回退到数据库查询
            placeholders = ','.join(['%s'] * len(trading_days))
            sql = f"""
            SELECT trade_date FROM new_stock_daily 
            WHERE stock_code = %s AND trade_date IN ({placeholders})
            """
            synced_dates = self.db_manager.execute_query(sql, (stock_code, *trading_days))
            synced_date_list = [row['trade_date'].strftime('%Y-%m-%d') for row in synced_dates]
            
            missing_days = [day for day in trading_days if day not in synced_date_list]
            return missing_days
            
        except Exception as e:
            logger.error(f"获取股票 {stock_code} 缺失交易日失败: {e}")
            return []

    def convert_stock_code_to_tushare(self, stock_code: str) -> str:
        """将股票代码转换为Tushare格式"""
        if stock_code.startswith('6'):
            return f"{stock_code}.SH"  # 上海交易所
        elif stock_code.startswith('0') or stock_code.startswith('3'):
            return f"{stock_code}.SZ"  # 深圳交易所
        elif stock_code.startswith('8') or stock_code.startswith('4'):
            return f"{stock_code}.BJ"  # 北京交易所
        else:
            return stock_code
    
    def get_daily_data_tushare(self, stock_code: str, start_date: str = None, end_date: str = None) -> pd.DataFrame:
        """使用Tushare获取单只股票的日线数据"""
        try:
            if not start_date:
                start_date = (datetime.now() - timedelta(days=365)).strftime('%Y%m%d')
            if not end_date:
                end_date = self.get_sync_end_date()
            
            # 转换股票代码为Tushare格式
            ts_code = self.convert_stock_code_to_tushare(stock_code)
            
            logger.debug(f"正在获取 {ts_code} 的日线数据，日期范围: {start_date} - {end_date}")
            
            # 使用Tushare获取日线数据，带重试机制
            df = None
            for attempt in range(self.max_retries):
                try:
                    # 注意：daily接口不支持turnover_rate字段，需要使用daily_basic接口获取
                    df = self.tushare_pro.daily(
                        ts_code=ts_code,
                        start_date=start_date,
                        end_date=end_date,
                        fields='trade_date,open,high,low,close,vol,amount,pct_chg'
                    )
                    
                    # Tushare 限流等待
                    time.sleep(self.request_delay)
                    break
                    
                except Exception as e:
                    error_msg = str(e)
                    
                    # 检查是否是权限或限流错误
                    if "抱歉，您每分钟最多访问" in error_msg:
                        logger.warning(f"触发 Tushare 限流，等待30秒后重试...")
                        time.sleep(30)
                        if attempt < self.max_retries - 1:
                            continue
                    
                    if "没有权限" in error_msg or "权限不足" in error_msg:
                        logger.error(f"Tushare 权限不足: {e}")
                        raise SystemExit("Tushare 权限不足，请检查 token 或升级账户")
                    
                    if attempt < self.max_retries - 1:
                        logger.warning(f"获取 {ts_code} 数据失败，第 {attempt + 1} 次重试: {e}")
                        time.sleep(5)
                    else:
                        raise e
            
            if df is None or df.empty:
                logger.warning(f"股票 {ts_code} 没有获取到数据")
                return pd.DataFrame()
            
            # Tushare 返回的日期是倒序的，需要排序
            df = df.sort_values('trade_date')
            
            # 重命名列以匹配数据库字段
            df.rename(columns={
                "trade_date": "trade_date",
                "open": "open_price",
                "high": "high_price",
                "low": "low_price",
                "close": "close_price",
                "vol": "volume",  # Tushare的成交量单位是手（100股）
                "amount": "amount",  # 单位：千元
                "pct_chg": "change_pct"
            }, inplace=True)
            
            # 添加股票代码
            df['stock_code'] = stock_code
            
            # Tushare 数据单位转换
            df['volume'] = df['volume'] * 100  # 手转为股
            df['amount'] = df['amount'] * 1000  # 千元转为元
            
            # 计算其他字段（Tushare不直接提供这些字段）
            df['change_amount'] = df['close_price'] * df['change_pct'] / 100
            df['amplitude'] = ((df['high_price'] - df['low_price']) / df['close_price'].shift(1) * 100).round(2)
            
            # Tushare的daily接口不提供turnover_rate，设置为None
            # 如果需要换手率，可以调用daily_basic接口单独获取
            df['turnover_rate'] = None
            
            # 选择需要的列
            required_columns = ['stock_code', 'trade_date', 'open_price', 'high_price', 'low_price', 'close_price',
                              'volume', 'amount', 'amplitude', 'change_pct', 'change_amount', 'turnover_rate']
            df = df[required_columns]
            
            # 处理数据类型
            df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d').dt.date
            df['open_price'] = pd.to_numeric(df['open_price'], errors='coerce')
            df['high_price'] = pd.to_numeric(df['high_price'], errors='coerce')
            df['low_price'] = pd.to_numeric(df['low_price'], errors='coerce')
            df['close_price'] = pd.to_numeric(df['close_price'], errors='coerce')
            df['volume'] = pd.to_numeric(df['volume'], errors='coerce')
            df['amount'] = pd.to_numeric(df['amount'], errors='coerce')
            df['amplitude'] = pd.to_numeric(df['amplitude'], errors='coerce')
            df['change_pct'] = pd.to_numeric(df['change_pct'], errors='coerce')
            df['change_amount'] = pd.to_numeric(df['change_amount'], errors='coerce')
            df['turnover_rate'] = pd.to_numeric(df['turnover_rate'], errors='coerce')
            
            # 删除无效数据
            df = df.dropna(subset=['open_price', 'high_price', 'low_price', 'close_price', 'volume'])
            
            # 将NaN转换为None（NULL），避免MySQL插入错误
            # 使用replace方法，更可靠
            import numpy as np
            df = df.replace({np.nan: None})
            
            logger.debug(f"成功获取 {ts_code} 的日线数据: {len(df)} 条记录")
            return df
            
        except Exception as e:
            logger.error(f"Tushare获取股票 {stock_code} 日线数据失败: {e}")
            return pd.DataFrame()
    
    def get_daily_data_akshare(self, stock_code: str, start_date: str = None, end_date: str = None) -> pd.DataFrame:
        """使用AKShare获取单只股票的日线数据"""
        try:
            # 如果没有指定日期，默认获取最近1年的数据
            if not start_date:
                start_date = (datetime.now() - timedelta(days=365)).strftime('%Y%m%d')
            if not end_date:
                end_date = self.get_sync_end_date()  # 使用同步结束日期（考虑15点限制）
            
            # akshare使用不带后缀的股票代码
            symbol = stock_code
            
            logger.debug(f"正在获取 {symbol} 的日线数据，日期范围: {start_date} - {end_date}")
            
            # 使用akshare获取日线数据，带重试机制
            df = None
            for attempt in range(self.max_retries):
                try:
                    df = ak.stock_zh_a_hist(
                        symbol=symbol,
                        period="daily",
                        start_date=start_date,
                        end_date=end_date,
                        adjust="qfq"  # 前复权
                    )
                    self.consecutive_errors = 0  # 成功后重置错误计数
                    break  # 成功获取数据，跳出重试循环
                except Exception as e:
                    error_msg = str(e)
                    self.consecutive_errors += 1
                    
                    # 检查是否是连接被拒绝或限流错误
                    if "Connection aborted" in error_msg or "Remote end closed connection" in error_msg or "频繁" in error_msg or "拒绝" in error_msg:
                        logger.warning(f"检测到限流或连接问题: {e}")
                        # 使用更长的延迟
                        if attempt < self.max_retries - 1:
                            # 根据尝试次数递增延迟时间
                            backoff_delay = self.request_delay_on_error * (attempt + 1)
                            logger.warning(f"获取 {symbol} 数据失败，等待 {backoff_delay} 秒后重试（第{attempt + 1}次）...")
                            time.sleep(backoff_delay)
                        else:
                            # 如果已经多次失败，建议用户增加延迟
                            if self.consecutive_errors >= 5:
                                logger.error(f"连续多次失败，建议增加 request_delay_min/max 配置")
                            raise e
                    else:
                        # 其他错误，使用较短的重试延迟
                        if attempt < self.max_retries - 1:
                            logger.warning(f"获取 {symbol} 数据失败，第 {attempt + 1} 次重试: {e}")
                            time.sleep(2)  # 重试前等待2秒
                        else:
                            raise e  # 最后一次重试失败，抛出异常
            
            if df.empty:
                logger.warning(f"股票 {symbol} 没有获取到数据")
                return pd.DataFrame()
            
            # 重命名列
            df.rename(columns={
                "日期": "trade_date",
                "开盘": "open_price",
                "收盘": "close_price",
                "最高": "high_price",
                "最低": "low_price",
                "成交量": "volume",
                "成交额": "amount",
                "振幅": "amplitude",
                "涨跌幅": "change_pct",
                "涨跌额": "change_amount",
                "换手率": "turnover_rate"
            }, inplace=True)
            
            # 添加股票代码
            df['stock_code'] = stock_code
            
            # 选择需要的列
            required_columns = ['stock_code', 'trade_date', 'open_price', 'high_price', 'low_price', 'close_price', 
                              'volume', 'amount', 'amplitude', 'change_pct', 'change_amount', 'turnover_rate']
            df = df[required_columns]
            
            # 处理数据类型
            df['trade_date'] = pd.to_datetime(df['trade_date']).dt.date
            df['open_price'] = pd.to_numeric(df['open_price'], errors='coerce')
            df['high_price'] = pd.to_numeric(df['high_price'], errors='coerce')
            df['low_price'] = pd.to_numeric(df['low_price'], errors='coerce')
            df['close_price'] = pd.to_numeric(df['close_price'], errors='coerce')
            df['volume'] = pd.to_numeric(df['volume'], errors='coerce')
            df['amount'] = pd.to_numeric(df['amount'], errors='coerce')
            df['amplitude'] = pd.to_numeric(df['amplitude'], errors='coerce')
            df['change_pct'] = pd.to_numeric(df['change_pct'], errors='coerce')
            df['change_amount'] = pd.to_numeric(df['change_amount'], errors='coerce')
            df['turnover_rate'] = pd.to_numeric(df['turnover_rate'], errors='coerce')
            
            # 删除无效数据
            df = df.dropna(subset=['open_price', 'high_price', 'low_price', 'close_price', 'volume'])
            
            logger.debug(f"成功获取 {symbol} 的日线数据: {len(df)} 条记录")
            return df
            
        except Exception as e:
            logger.error(f"AKShare获取股票 {stock_code} 日线数据失败: {e}")
            return pd.DataFrame()

    def get_daily_data(self, stock_code: str, start_date: str = None, end_date: str = None) -> pd.DataFrame:
        """获取单只股票的日线数据（根据配置选择数据源）"""
        if self.data_source == 'tushare':
            return self.get_daily_data_tushare(stock_code, start_date, end_date)
        else:
            return self.get_daily_data_akshare(stock_code, start_date, end_date)
    
    def get_daily_data_by_date_tushare(self, trade_date: str) -> pd.DataFrame:
        """使用Tushare按日期批量获取所有股票的日线数据
        
        Args:
            trade_date: 交易日期，格式：YYYYMMDD
            
        Returns:
            包含所有股票当天数据的DataFrame
        """
        try:
            logger.info(f"正在批量获取 {trade_date} 所有股票的日线数据...")
            
            # 使用Tushare获取指定日期所有股票的数据，带重试机制
            df = None
            for attempt in range(self.max_retries):
                try:
                    df = self.tushare_pro.daily(
                        trade_date=trade_date,
                        fields='ts_code,trade_date,open,high,low,close,vol,amount,pct_chg'
                    )
                    
                    # Tushare 限流等待
                    time.sleep(self.request_delay)
                    break
                    
                except Exception as e:
                    error_msg = str(e)
                    
                    # 检查是否是权限或限流错误
                    if "抱歉，您每分钟最多访问" in error_msg:
                        logger.warning(f"触发 Tushare 限流，等待30秒后重试...")
                        time.sleep(30)
                        if attempt < self.max_retries - 1:
                            continue
                    
                    if "没有权限" in error_msg or "权限不足" in error_msg:
                        logger.error(f"Tushare 权限不足: {e}")
                        raise SystemExit("Tushare 权限不足，请检查 token 或升级账户")
                    
                    if attempt < self.max_retries - 1:
                        logger.warning(f"获取 {trade_date} 数据失败，第 {attempt + 1} 次重试: {e}")
                        time.sleep(5)
                    else:
                        raise e
            
            if df is None or df.empty:
                logger.warning(f"{trade_date} 没有获取到数据（可能不是交易日）")
                return pd.DataFrame()
            
            logger.info(f"✓ 获取到 {len(df)} 只股票的数据")
            
            # 数据处理
            # 提取股票代码（去除交易所后缀）
            df['stock_code'] = df['ts_code'].str.split('.').str[0]
            
            # 重命名列以匹配数据库字段
            df.rename(columns={
                "trade_date": "trade_date",
                "open": "open_price",
                "high": "high_price",
                "low": "low_price",
                "close": "close_price",
                "vol": "volume",
                "amount": "amount",
                "pct_chg": "change_pct"
            }, inplace=True)
            
            # Tushare 数据单位转换
            df['volume'] = df['volume'] * 100  # 手转为股
            df['amount'] = df['amount'] * 1000  # 千元转为元
            
            # 计算其他字段
            df['change_amount'] = df['close_price'] * df['change_pct'] / 100
            
            # 批量获取时，振幅需要前一日收盘价，这里先设为None
            # 可以在后续处理中通过查询数据库补充
            df['amplitude'] = None
            df['turnover_rate'] = None
            
            # 选择需要的列
            required_columns = ['stock_code', 'trade_date', 'open_price', 'high_price', 'low_price', 'close_price',
                              'volume', 'amount', 'amplitude', 'change_pct', 'change_amount', 'turnover_rate']
            df = df[required_columns]
            
            # 处理数据类型
            df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d').dt.date
            df['open_price'] = pd.to_numeric(df['open_price'], errors='coerce')
            df['high_price'] = pd.to_numeric(df['high_price'], errors='coerce')
            df['low_price'] = pd.to_numeric(df['low_price'], errors='coerce')
            df['close_price'] = pd.to_numeric(df['close_price'], errors='coerce')
            df['volume'] = pd.to_numeric(df['volume'], errors='coerce')
            df['amount'] = pd.to_numeric(df['amount'], errors='coerce')
            df['amplitude'] = pd.to_numeric(df['amplitude'], errors='coerce')
            df['change_pct'] = pd.to_numeric(df['change_pct'], errors='coerce')
            df['change_amount'] = pd.to_numeric(df['change_amount'], errors='coerce')
            df['turnover_rate'] = pd.to_numeric(df['turnover_rate'], errors='coerce')
            
            # 删除无效数据
            df = df.dropna(subset=['open_price', 'high_price', 'low_price', 'close_price', 'volume'])
            
            # 将NaN转换为None（NULL），避免MySQL插入错误
            import numpy as np
            df = df.replace({np.nan: None})
            
            logger.info(f"✓ 处理后有效数据: {len(df)} 条")
            return df
            
        except Exception as e:
            logger.error(f"批量获取 {trade_date} 数据失败: {e}")
            return pd.DataFrame()
    
    def sync_single_stock(self, stock_code: str, max_days: int = 365) -> Dict[str, Any]:
        """同步单只股票的日线数据（优化版：按日期分批获取并立即保存）"""
        result = {
            'stock_code': stock_code,
            'success': False,
            'records_count': 0,
            'error': None
        }
        
        try:
            # 获取缺失的交易日列表
            missing_days = self.get_missing_trading_days(stock_code)
            
            if not missing_days:
                result['success'] = True
                result['records_count'] = 0
                logger.info(f"股票 {stock_code} 数据已是最新，跳过同步")
                return result
            
            logger.info(f"股票 {stock_code} 需要同步 {len(missing_days)} 个交易日")
            
            # 按日期范围分批获取数据
            total_synced = 0
            batch_size = 30  # 每次最多获取30天的数据
            
            for i in range(0, len(missing_days), batch_size):
                batch_days = missing_days[i:i + batch_size]
                start_date = batch_days[0].replace('-', '')
                end_date = batch_days[-1].replace('-', '')
                
                logger.debug(f"获取股票 {stock_code} 数据，日期范围: {start_date} - {end_date}")
                
                # 获取日线数据
                df = self.get_daily_data(stock_code, start_date, end_date)
                
                if not df.empty:
                    # 立即保存到数据库
                    batch_data = df.to_dict('records')
                    synced_count = self.daily_dao.batch_insert_or_update_daily_data(batch_data)
                    total_synced += synced_count
                    logger.debug(f"股票 {stock_code} 批次同步完成，新增 {synced_count} 条记录")
                else:
                    logger.warning(f"股票 {stock_code} 在 {start_date}-{end_date} 期间没有数据")
                
                # 添加延迟，避免请求过于频繁（批次间延迟）
                # 如果有连续错误，使用更长的延迟；否则使用随机延迟
                if i < len(missing_days) - batch_size:  # 不是最后一批
                    if self.consecutive_errors >= 3:
                        time.sleep(self.request_delay_on_error)
                    else:
                        time.sleep(self.get_random_delay())
            
            result['success'] = True
            result['records_count'] = total_synced
            logger.info(f"股票 {stock_code} 同步完成，共新增 {total_synced} 条记录")
            
            # 更新缓存中的最新日期
            if total_synced > 0 and missing_days:
                # 更新为最新的同步日期
                latest_synced_date = missing_days[-1].replace('-', '')
                self.update_stock_latest_date(stock_code, latest_synced_date)
            
        except Exception as e:
            result['error'] = str(e)
            logger.error(f"股票 {stock_code} 同步失败: {e}")
        
        return result
    
    def pre_analyze_sync_needs(self, stock_codes: List[str] = None, max_days: int = 365) -> Dict[str, Any]:
        """预先分析所有股票的同步需求"""
        if not stock_codes:
            stock_codes = self.get_stock_codes()
        
        logger.info(f"开始分析 {len(stock_codes)} 只股票的同步需求...")
        
        needs_sync = []
        skip_reasons = {}
        total_sync_days = 0
        
        for i, stock_code in enumerate(stock_codes, 1):
            if i % 100 == 0:
                logger.info(f"已分析 {i}/{len(stock_codes)} 只股票...")
            
            sync_info = self.calculate_sync_dates(stock_code, max_days)
            
            if sync_info['needs_sync']:
                needs_sync.append(sync_info)
                total_sync_days += sync_info['sync_days']
            else:
                reason = sync_info['reason']
                if reason not in skip_reasons:
                    skip_reasons[reason] = 0
                skip_reasons[reason] += 1
        
        analysis_result = {
            'total_stocks': len(stock_codes),
            'needs_sync_count': len(needs_sync),
            'skip_count': len(stock_codes) - len(needs_sync),
            'total_sync_days': total_sync_days,
            'needs_sync_stocks': needs_sync,
            'skip_reasons': skip_reasons
        }
        
        logger.info(f"分析完成！需要同步: {len(needs_sync)} 只，跳过: {len(stock_codes) - len(needs_sync)} 只，总交易日数: {total_sync_days}")
        
        return analysis_result
    
    def print_progress(self, current: int, total: int, stock_code: str, status: str):
        """打印同步进度"""
        progress = (current / total) * 100
        bar_length = 30
        filled_length = int(bar_length * current // total)
        bar = '█' * filled_length + '-' * (bar_length - filled_length)
        print(f'\r进度: |{bar}| {progress:.1f}% ({current}/{total}) - {stock_code}: {status}', end='', flush=True)
    
    def sync_daily_data_by_date_batch(self, days: int = 30) -> Dict[str, Any]:
        """按日期批量同步所有股票的日线数据（Tushare专用）
        
        这是一种更高效的同步方式：
        - 按日期批量获取所有股票的数据，而不是逐个股票获取
        - 大大减少API调用次数（30天只需30次调用，而不是5000+股票的调用）
        - 适合用于日常增量更新
        
        Args:
            days: 要同步的天数（默认30天）
            
        Returns:
            同步结果字典
        """
        start_time = datetime.now()
        result = {
            'success': False,
            'total_days': 0,
            'synced_days': 0,
            'total_records': 0,
            'synced_records': 0,
            'error': None,
            'duration': 0,
            'skipped_days': 0
        }
        
        try:
            if self.data_source != 'tushare':
                raise ValueError(f"批量同步仅支持 Tushare 数据源，当前数据源为: {self.data_source}")
            
            # 获取需要同步的交易日列表
            end_date = self.get_sync_end_date()
            end_date_str = f"{end_date[:4]}-{end_date[4:6]}-{end_date[6:8]}"
            
            start_date_obj = datetime.strptime(end_date, '%Y%m%d') - timedelta(days=days)
            start_date_str = start_date_obj.strftime('%Y-%m-%d')
            
            trading_days = self.trading_calendar.get_trading_days(start_date_str, end_date_str)
            
            if not trading_days:
                logger.warning("没有找到交易日")
                result['success'] = True
                return result
            
            result['total_days'] = len(trading_days)
            
            print("=" * 60)
            print("按日期批量同步股票日线数据")
            print("=" * 60)
            print(f"数据源: Tushare")
            print(f"日期范围: {trading_days[0]} - {trading_days[-1]}")
            print(f"交易日数: {len(trading_days)} 天")
            print(f"预计API调用次数: {len(trading_days)} 次")
            print("=" * 60)
            
            synced_days = 0
            total_synced_records = 0
            skipped_days = 0
            
            # 逐个交易日批量获取数据
            for i, trade_date_str in enumerate(trading_days, 1):
                trade_date = trade_date_str.replace('-', '')
                
                try:
                    print(f"\n[{i}/{len(trading_days)}] 同步 {trade_date_str} 的数据...")
                    
                    # 检查该日期是否已经同步过
                    check_sql = "SELECT COUNT(*) as count FROM new_stock_daily WHERE trade_date = %s"
                    count_result = self.db_manager.execute_query(check_sql, (trade_date_str,))
                    existing_count = count_result[0]['count'] if count_result else 0
                    
                    if existing_count > 5000:  # 如果已有大量数据，跳过
                        print(f"  ✓ 该日期已有 {existing_count} 条记录，跳过")
                        skipped_days += 1
                        continue
                    
                    # 批量获取该日期所有股票的数据
                    df = self.get_daily_data_by_date_tushare(trade_date)
                    
                    if df.empty:
                        print(f"  - 没有获取到数据")
                        skipped_days += 1
                        continue
                    
                    # 批量插入数据库
                    batch_data = df.to_dict('records')
                    inserted_count = self.daily_dao.batch_insert_or_update_daily_data(batch_data)
                    
                    total_synced_records += inserted_count
                    synced_days += 1
                    
                    print(f"  ✓ 成功同步 {len(df)} 只股票，插入/更新 {inserted_count} 条记录")
                    
                except Exception as e:
                    logger.error(f"同步 {trade_date_str} 数据失败: {e}")
                    print(f"  ✗ 同步失败: {e}")
                    continue
            
            result['success'] = True
            result['synced_days'] = synced_days
            result['synced_records'] = total_synced_records
            result['total_records'] = total_synced_records
            result['skipped_days'] = skipped_days
            
            print("\n" + "=" * 60)
            print("批量同步完成统计")
            print("=" * 60)
            print(f"总交易日: {len(trading_days)} 天")
            print(f"成功同步: {synced_days} 天")
            print(f"跳过天数: {skipped_days} 天")
            print(f"总记录数: {total_synced_records} 条")
            print(f"平均每天: {total_synced_records // synced_days if synced_days > 0 else 0} 条")
            
        except Exception as e:
            result['error'] = str(e)
            logger.error(f"批量同步失败: {e}")
        
        finally:
            end_time = datetime.now()
            result['duration'] = (end_time - start_time).total_seconds()
            print(f"同步耗时: {result['duration']:.2f} 秒")
            print("=" * 60)
        
        return result
    
    def sync_daily_data(self, stock_codes: List[str] = None, max_days: int = 365, 
                       auto_manage: bool = True, use_batch_mode: bool = False) -> Dict[str, Any]:
        """同步股票日线数据（基于股票状态智能管理）
        
        Args:
            stock_codes: 股票代码列表，如果为None则同步所有活跃股票
            max_days: 最大同步天数
            auto_manage: 是否启用智能管理（自动清理无效股票等）
            use_batch_mode: 是否使用批量模式（仅Tushare支持，按日期批量获取所有股票）
        """
        # 如果启用批量模式且数据源是Tushare，使用批量同步
        if use_batch_mode and self.data_source == 'tushare':
            logger.info("使用批量同步模式")
            return self.sync_daily_data_by_date_batch(days=max_days)
        
        start_time = datetime.now()
        result = {
            'success': False,
            'total_stocks': 0,
            'successful_stocks': 0,
            'failed_stocks': 0,
            'total_records': 0,
            'synced_records': 0,
            'error': None,
            'duration': 0,
            'failed_list': [],
            'skip_count': 0,
            'skip_reasons': {},
            'cleaned_records': 0,
            'new_stocks_synced': 0,
            'active_stocks_synced': 0,
            'delisted_stocks_skipped': 0
        }
        
        try:
            # 如果启用自动管理，基于股票状态决定同步策略
            if auto_manage:
                print("启用智能同步管理，基于股票状态决定同步策略...")
                
                # 1. 清理无效股票的日线数据
                cleaned_count = self.cleanup_daily_data_for_invalid_stocks()
                result['cleaned_records'] = cleaned_count
                
                # 2. 分析需要同步的股票
                sync_analysis = self.get_stocks_needing_daily_sync()
                
                # 合并需要同步的股票（活跃股票 + 新增股票）
                stocks_to_sync = sync_analysis['active_stocks'] + sync_analysis['new_stocks']
                delisted_stocks = sync_analysis['delisted_stocks']
                
                result['new_stocks_synced'] = len(sync_analysis['new_stocks'])
                result['active_stocks_synced'] = len(sync_analysis['active_stocks'])
                result['delisted_stocks_skipped'] = len(delisted_stocks)
                
                print(f"同步策略分析完成:")
                print(f"  活跃股票（继续同步）: {len(sync_analysis['active_stocks'])} 只")
                print(f"  新增股票（开始同步）: {len(sync_analysis['new_stocks'])} 只")
                print(f"  退市股票（跳过同步）: {len(delisted_stocks)} 只")
                print(f"  清理无效数据: {cleaned_count} 条")
                
                if not stocks_to_sync:
                    print("没有需要同步的股票，所有数据已是最新状态")
                    result['success'] = True
                    result['total_stocks'] = 0
                    result['successful_stocks'] = 0
                    return result
                
                stock_codes = stocks_to_sync
            else:
                # 传统模式：手动指定股票代码或获取所有活跃股票
                if not stock_codes:
                    stock_codes = self.get_stock_codes()
            
            result['total_stocks'] = len(stock_codes)
            print(f"开始同步 {len(stock_codes)} 只股票的日线数据...")
            
            # 加载股票最新同步日期缓存
            print("正在加载股票最新同步日期缓存...")
            self.load_stock_latest_dates(stock_codes)
            
            successful_count = 0
            failed_count = 0
            failed_list = []
            total_synced_records = 0
            skip_count = 0
            skip_reasons = {}
            
            # 逐个分析并处理股票数据（使用缓存优化）
            for i, stock_code in enumerate(stock_codes, 1):
                try:
                    # 使用缓存优化的方法检查是否需要同步
                    missing_days = self.get_missing_trading_days(stock_code)
                    
                    if not missing_days:
                        # 跳过不需要同步的股票
                        skip_count += 1
                        reason = "数据已是最新"
                        if reason not in skip_reasons:
                            skip_reasons[reason] = 0
                        skip_reasons[reason] += 1
                        
                        # 只显示进度，不显示详细原因
                        self.print_progress(i, len(stock_codes), stock_code, "跳过")
                        continue
                    
                    # 需要同步的股票，立即处理
                    sync_days = len(missing_days)
                    
                    # 显示同步信息
                    print(f"\n[{i}/{len(stock_codes)}] 同步 {stock_code} ({sync_days}个交易日)")
                    
                    # 同步单只股票（获取数据后立即保存到数据库）
                    stock_result = self.sync_single_stock(stock_code, max_days)
                    
                    if stock_result['success']:
                        successful_count += 1
                        total_synced_records += stock_result['records_count']
                        if stock_result['records_count'] > 0:
                            status = f"✓ 已保存 {stock_result['records_count']} 条记录"
                            print(f"  {status}")
                        else:
                            status = "✓ 数据已是最新"
                            print(f"  {status}")
                    else:
                        failed_count += 1
                        failed_list.append(stock_code)
                        status = f"✗ 同步失败: {stock_result['error']}"
                        print(f"  {status}")
                    
                    # 更新进度显示
                    self.print_progress(i, len(stock_codes), stock_code, "完成")
                    
                    # 每只股票处理完成后添加延迟，避免频率限制
                    # 如果有连续错误，使用更长的延迟；否则使用随机延迟
                    if i < len(stock_codes):  # 最后一只股票不需要延迟
                        if self.consecutive_errors >= 3:
                            time.sleep(self.request_delay_on_error)
                        else:
                            time.sleep(self.get_random_delay())
                        
                except Exception as e:
                    failed_count += 1
                    failed_list.append(stock_code)
                    status = f"✗ 处理失败: {e}"
                    print(f"\n[{i}/{len(stock_codes)}] {stock_code}: {status}")
                    self.print_progress(i, len(stock_codes), stock_code, "失败")
                    continue
            
            # 完成进度显示
            print(f"\n同步完成！")
            
            result['success'] = True
            result['successful_stocks'] = successful_count
            result['failed_stocks'] = failed_count
            result['total_records'] = total_synced_records
            result['synced_records'] = total_synced_records
            result['failed_list'] = failed_list
            result['skip_count'] = skip_count
            result['skip_reasons'] = skip_reasons
            
            # 打印最终统计
            print("\n" + "=" * 60)
            print("日线数据同步完成统计")
            print("=" * 60)
            print(f"总股票数: {len(stock_codes)}")
            print(f"成功同步: {successful_count} 只")
            print(f"跳过股票: {skip_count} 只")
            print(f"失败股票: {failed_count} 只")
            print(f"总记录数: {total_synced_records} 条")
            
            if auto_manage:
                print(f"\n智能管理统计:")
                print(f"  清理无效数据: {result['cleaned_records']} 条")
                print(f"  新增股票同步: {result['new_stocks_synced']} 只")
                print(f"  活跃股票同步: {result['active_stocks_synced']} 只")
                print(f"  退市股票跳过: {result['delisted_stocks_skipped']} 只")
            
        except Exception as e:
            result['error'] = str(e)
            logger.error(f"日线数据同步失败: {e}")
        
        finally:
            end_time = datetime.now()
            result['duration'] = (end_time - start_time).total_seconds()
            logger.info(f"同步耗时: {result['duration']:.2f} 秒")
        
        return result
    
    def cleanup_daily_data_for_invalid_stocks(self) -> int:
        """清理不在股票信息表中的日线数据"""
        try:
            logger.info("开始清理无效股票的日线数据...")
            
            # 找出在日线数据表中但不在股票信息表中的股票代码
            cleanup_sql = """
            DELETE FROM new_stock_daily 
            WHERE stock_code NOT IN (
                SELECT stock_code FROM new_stock_info
            )
            """
            
            deleted_count = self.db_manager.execute_update(cleanup_sql)
            logger.info(f"已清理 {deleted_count} 条无效股票的日线数据")
            
            return deleted_count
            
        except Exception as e:
            logger.error(f"清理无效股票日线数据失败: {e}")
            return 0
    
    def get_stocks_needing_daily_sync(self) -> Dict[str, List[str]]:
        """获取需要同步日线数据的股票分类"""
        try:
            logger.info("分析需要同步日线数据的股票...")
            
            # 获取所有股票的同步状态
            stock_status = self.get_stock_sync_status()
            
            # 获取已有日线数据的股票
            existing_daily_sql = "SELECT DISTINCT stock_code FROM new_stock_daily"
            existing_daily_results = self.db_manager.execute_query(existing_daily_sql)
            existing_daily_stocks = set([row['stock_code'] for row in existing_daily_results])
            
            # 分类股票
            active_stocks = []
            new_stocks = []
            delisted_stocks = []
            
            for stock_code, info in stock_status.items():
                if info['status'] == 'active':
                    if stock_code not in existing_daily_stocks:
                        # 新增的活跃股票，需要开始同步日线数据
                        new_stocks.append(stock_code)
                    else:
                        # 已有的活跃股票，需要继续同步
                        active_stocks.append(stock_code)
                elif info['status'] == 'delisted':
                    # 退市股票，不再同步日线数据
                    delisted_stocks.append(stock_code)
            
            result = {
                'active_stocks': active_stocks,      # 需要继续同步的活跃股票
                'new_stocks': new_stocks,           # 新增需要同步的股票
                'delisted_stocks': delisted_stocks, # 退市股票（不再同步）
                'total_active': len(active_stocks),
                'total_new': len(new_stocks),
                'total_delisted': len(delisted_stocks)
            }
            
            logger.info(f"股票分类完成:")
            logger.info(f"  活跃股票（继续同步）: {len(active_stocks)} 只")
            logger.info(f"  新增股票（开始同步）: {len(new_stocks)} 只")
            logger.info(f"  退市股票（停止同步）: {len(delisted_stocks)} 只")
            
            return result
            
        except Exception as e:
            logger.error(f"分析需要同步的股票失败: {e}")
            return {
                'active_stocks': [],
                'new_stocks': [],
                'delisted_stocks': [],
                'total_active': 0,
                'total_new': 0,
                'total_delisted': 0
            }
    
    def get_sync_summary(self) -> Dict[str, Any]:
        """获取同步摘要信息"""
        try:
            # 获取数据库中的日线数据统计
            total_records = self.db_manager.execute_query('SELECT COUNT(*) as count FROM new_stock_daily')[0]['count']
            total_stocks = self.db_manager.execute_query('SELECT COUNT(DISTINCT stock_code) as count FROM new_stock_daily')[0]['count']
            
            # 获取最新和最旧的交易日期
            latest_date = self.db_manager.execute_query('SELECT MAX(trade_date) as date FROM new_stock_daily')[0]['date']
            earliest_date = self.db_manager.execute_query('SELECT MIN(trade_date) as date FROM new_stock_daily')[0]['date']
            
            return {
                'total_records': total_records,
                'total_stocks': total_stocks,
                'latest_date': latest_date.strftime('%Y-%m-%d') if latest_date else None,
                'earliest_date': earliest_date.strftime('%Y-%m-%d') if earliest_date else None,
                'last_sync': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            }
            
        except Exception as e:
            logger.error(f"获取同步摘要失败: {e}")
            return {
                'error': str(e),
                'total_records': 0,
                'total_stocks': 0,
                'latest_date': None,
                'earliest_date': None
            }

def main():
    """主函数"""
    try:
        # 创建同步器
        sync = StockDailySync()
        
        # 执行同步
        result = sync.sync_daily_data()
        
        # 打印结果
        if result['success']:
            print("=" * 60)
            print("A股日线数据同步成功！")
            print(f"处理股票数: {result['total_stocks']} 只")
            print(f"成功股票数: {result['successful_stocks']} 只")
            print(f"失败股票数: {result['failed_stocks']} 只")
            print(f"总记录数: {result['total_records']} 条")
            print(f"同步记录数: {result['synced_records']} 条")
            print(f"同步耗时: {result['duration']:.2f} 秒")
            
            # 显示智能管理统计
            if 'cleaned_records' in result and result['cleaned_records'] > 0:
                print(f"清理无效数据: {result['cleaned_records']} 条")
            if 'new_stocks_synced' in result and result['new_stocks_synced'] > 0:
                print(f"新增股票同步: {result['new_stocks_synced']} 只")
            if 'delisted_stocks_skipped' in result and result['delisted_stocks_skipped'] > 0:
                print(f"退市股票跳过: {result['delisted_stocks_skipped']} 只")
            
            if result['failed_list']:
                print(f"失败股票: {', '.join(result['failed_list'][:10])}{'...' if len(result['failed_list']) > 10 else ''}")
            print("=" * 60)
        else:
            print("=" * 60)
            print("A股日线数据同步失败！")
            print(f"错误信息: {result['error']}")
            print("=" * 60)
        
        # 显示同步摘要
        summary = sync.get_sync_summary()
        if 'error' not in summary:
            print("\n数据库当前状态:")
            print(f"总记录数: {summary['total_records']}")
            print(f"股票数: {summary['total_stocks']}")
            print(f"最新日期: {summary['latest_date']}")
            print(f"最早日期: {summary['earliest_date']}")
        
    except Exception as e:
        logger.error(f"程序执行失败: {e}")
        print(f"程序执行失败: {e}")

if __name__ == "__main__":
    main()
